import React, { PureComponent } from 'react';
import { Button, Form, Icon, message, Radio, Steps, Tabs, Upload } from 'antd';
import apiConfig from '@/apiConfig';
import request, { abortFetch, isLogin, jsonPost, newAbortCtrl, reqGet } from '@/helpers/request';
import { formatFilter } from '/common/utils/queryUtils';
import { getGID, getRandomKey, sleepFunc } from '/common/utils/utils';
import styles from './index.less';
import ExportDataBtn from '/common/componentsTpl/ButtonComp/ExportDataBtn';
import ImportExcelBtn from '/common/componentsTpl/ButtonComp/ImportExcelBtn';
import ModalComp from '/common/components/ModalItem/ModalComp';
import isEmpty from "lodash/isEmpty";
import isArray from "lodash/isArray";
import map from "lodash/map";
import find from "lodash/find";


const { TabPane } = Tabs;

/**
 * 导出表单
 */
@Form.create()
class ExPortForm extends PureComponent {

  componentDidMount() {
    this.props.onRef && this.props.onRef(this);
  }

  getAjaxData() {
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((errors, fieldsValue) => {

        if (isEmpty(errors)) {
          resolve({ ...fieldsValue });

        } else {
          reject(errors);
        }
      });
    });
  }

  render() {
    const { getFieldDecorator } = this.props.form;
    return (
      <Form layout="horizontal" labelAlign={'left'} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
        <Form.Item>
          {getFieldDecorator('exType', {
            initialValue: '1',
          })(
            <Radio.Group>
              <Radio value="1" className={'mr16'}>导出全部{this.props.cn || ''}</Radio>
              <Radio value="2" disabled={isEmpty(this.props.selectedKeys)}>导出选中{this.props.cn || ''}</Radio>
            </Radio.Group>,
          )}
        </Form.Item>
      </Form>
    );
  }
}

const importIcons = {
  's_1': <Icon className={'text-primary'} type={'loading'}/>,
  's_2': <Icon className={'text-success'} type="check-circle"/>,
  's_3': <Icon className={'text-danger'} type="close-circle"/>,
};

/**
 * 导入表单
 */
class ImportForm extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      curStep: 1,
      imStatusKey: '',

      randomKey: getRandomKey(),
    };
    this.importFiles = []; // 导入的文件数组，{originFileObj: File, status:'1: 正在导入；2:导入成功；3:导入失败；'}
    this.abortCtrls = {};
  }

  componentWillUnmount() {
    for (let k in this.abortCtrls) {
      abortFetch(this.abortCtrls[k]);
    }
  }

  clickDownload() {
    if (this.props.appCode) {
      // 先查询此应用是否已经配置了导入模板
      reqGet(apiConfig.isCreateConfApi, { appCode: this.props.appCode }).then(rsp => {
        if (false === rsp) {
          message.error('下载失败：系统未配置导入模板文件');
        } else {
          window.open(`${apiConfig.exportTemplateApi}?appCode=${this.props.appCode}`, '_blank');
          this.clickNext();
        }
      });
    }
  }

  clickNext() {
    this.setState({ curStep: this.state.curStep + 1 });
  }

  clickPrev() {
    this.setState({ curStep: this.state.curStep - 1 });
  }

  clickDone() {
    this.clickCancel();
  }

  clickCancel() {
    this.props.onCancel && this.props.onCancel();
  }

  /**
   * 导入
   * */
  upload(file, uid, statusKey) {
    const $this = this;
    let formData = new FormData();
    formData.append('Filedata', file);

    let upKey = `upload_${uid}`;
    this.abortCtrls[upKey] = newAbortCtrl();
    return request(`${apiConfig.importExcelAPi}?statusKey=${statusKey}`, {
      method: 'POST',
      data: formData,
      contentType: 'multipart/form-data',
      signal: this.abortCtrls[upKey].signal,
    }).then(res => {
      $this.abortCtrls[upKey].signal.noAbort = true;
      isLogin(res);
      return res;
    });
  }

  beforeUpload = (file) => {

    // 先查询此应用是否已经配置了导入模板
    reqGet(apiConfig.isCreateConfApi, { appCode: this.props.appCode }).then(rsp => {
      if (false === rsp) {
        message.error('操作失败：系统未配置导入模板文件');
      } else {

        if (-1 !== file.type.indexOf('sheet') || -1 !== file.type.indexOf('excel')) {
          let uid = getGID();
          const fileObj = {
            uid,
            name: file.name,
            originFileObj: file,
            status: 1,
          };
          this.importFiles.push(fileObj);

          let $this = this;
          let imStatusKey = getRandomKey();
          this.setState({ imStatusKey });
          $this.upload(file, uid, imStatusKey).then((rsp) => {
            if (rsp && rsp.status === 200) {
              $this.reqExResult(imStatusKey, uid);
              // $this.props.afterImport && ($this.props.afterImport($this.state.imStatusKey,
              //   (statusKey, res) => {
              //     if (res && 200 === res.status && res.data) {
              //       // 改变文件的导入状态
              //       // 如果文件导入状态有变，则更新此组件
              //       if (fileObj.status != res.data.status) {
              //         fileObj.status = res.data.status;
              //         $this.setState({ randomKey: getRandomKey() });
              //       }
              //     }
              //   }));
            } else {
              fileObj.status = 3;
              message.error(rsp && rsp.msg ? rsp.msg : '导入失败');
            }
            $this.setState({ randomKey: getRandomKey() });
          });
        } else {
          message.error('请选择 Excel 文件');
        }
      }
    });

    return false;
  };

  /**
   * 查询导出结果，如果没完成，则轮询查询接口
   * @param statusKey
   * @param uid
   */
  reqExResult(statusKey, uid) {
    const $this = this;
    let newAbortIns, taskGroup;
    let resultKey = `result_${uid}`;

    this.abortCtrls[resultKey] = newAbortCtrl();
    newAbortIns = this.abortCtrls[resultKey];
    taskGroup = 'IMPORT_DATA';

    reqGet(apiConfig.exResultAPi, {
      statusKey,
      taskGroup,
      signal: newAbortIns.signal,
    }).then(rsp => {
      const fileObj = find($this.importFiles, v => v.uid === uid);

      if (fileObj) {
        if (rsp && rsp.status === 200 && rsp.data) {
          fileObj.status = rsp.data.status;

          if (1 >= fileObj.status) { // 导入还在进行，延迟 1s 后，如果文件还在导入，则继续轮询
            sleepFunc(1000).then(() => {
              const fObj = find($this.importFiles, v => v.uid === uid);
              if (fObj) {
                $this.reqExResult(statusKey, uid);
              }
            });
          } else if (2 == fileObj.status) {
            $this.props.afterImport && ($this.props.afterImport($this.hadAllImported(), 2));
          }
          $this.setState({ randomKey: getRandomKey() });
        } else {
          fileObj.status = 3;
          $this.setState({ randomKey: getRandomKey() });
        }
      }
      $this.props.afterImport && ($this.props.afterImport($this.hadAllImported()));
    });
  }

  deleteFile = (uid) => {
    this.importFiles = this.importFiles.filter(v => v.uid !== uid);
    let upKey = `upload_${uid}`;

    if (this.abortCtrls[upKey]) {
      abortFetch(this.abortCtrls[upKey]);
    }
    this.setState({ randomKey: getRandomKey() });
    this.props.afterImport && (this.props.afterImport(this.hadAllImported()));
  };

  hadAllImported() {
    return this.importFiles.filter(v => (1 == v.status)).length === 0;
  }

  render() {
    const { cn } = this.props;
    const { curStep } = this.state;
    const isAllImport = this.hadAllImported();
    const imLoading = !isAllImport;

    return (
      <>
        <Steps size={'small'} className={styles.steps} current={curStep - 1}>
          <Steps.Step title={'下载模板'}/>
          <Steps.Step title={`导入${cn}`}/>
        </Steps>
        <Tabs activeKey={`${curStep}`} renderTabBar={() => <div/>}>
          <TabPane tab="下载模板" key="1">
            <div className={styles.box}>
              <div className={styles.boxTip}>请点击下面的按钮下载模板，并填写{cn}信息</div>
              <Button style={{ margin: 16 }} type={'primary'}
                      onClick={this.clickDownload.bind(this)}><Icon type="download"/> 下载{cn}模板</Button>
            </div>
          </TabPane>
          <TabPane tab="导入数据" key="2">
            <div className={styles.box}>
              {
                !isEmpty(this.importFiles) ? (
                  map(this.importFiles, v => (
                    <div key={v.uid} className={`${styles.boxTip} text-left`}>
                      {importIcons[`s_${v.status}`]} {v.name}
                      <a href="javascript:;" className={styles.delBtn} onClick={this.deleteFile.bind(this, v.uid)}>
                        <Icon type={'close'}/> </a>
                    </div>
                  ))
                ) : (
                  <div className={styles.boxTip}>
                    导入已完成的{cn}模板 Excel 文件
                  </div>
                )
              }
              <Upload
                disabled={imLoading}
                accept={'.xls,.xlsx'}
                showUploadList={false}
                beforeUpload={this.beforeUpload}
              >
                <Button disabled={imLoading} style={{ margin: 16 }} type={'primary'}><Icon
                  type="upload"/> {
                  !isEmpty(this.importFiles) ? `继续导入` : `上传${cn}模板`
                }</Button>
              </Upload>
            </div>
          </TabPane>
        </Tabs>
        <div className={styles.footer}>
          {
            1 === curStep && (
              <>
                <Button onClick={this.clickCancel.bind(this)}>取消</Button>
                <Button type={'primary'} onClick={this.clickNext.bind(this)}>下一步</Button>
              </>
            )
          }
          {
            2 === curStep && (
              <>
                <Button type={'primary'} onClick={this.clickPrev.bind(this)}>上一步</Button>
                <Button loading={!isAllImport} type={'primary'} onClick={this.clickDone.bind(this)}>完成</Button>
              </>
            )
          }
        </div>
      </>
    );
  }
}

/**
 * 导出/导入
 */
class ExportComp extends PureComponent {

  constructor(props) {
    super(props);
    this.state = {
      showExModal: false,
      exLoading: false,

      showImModal: false,
      imLoading: false,
    };
    this.abortCtrls = {};
    this.needReqResult = false; // 标识是否需要轮询"导入导出结果"接口
  }

  componentWillUnmount() {
    this.abortAllFetch();
  }

  abortAllFetch(type) {

    if ('ex' === type) {
      this.needReqResult = false;
      abortFetch(this.abortCtrls.export);
      abortFetch(this.abortCtrls.exResult);

    } else if ('im' === type) {
      abortFetch(this.abortCtrls.import);
      abortFetch(this.abortCtrls.imResult);

    } else {
      this.needReqResult = false;

      for (let k in this.abortCtrls) {
        abortFetch(this.abortCtrls[k]);
      }
    }

  }

  clickExport() {
    if (this.props.needExModal) {
      this.setState({ showExModal: true });
    } else {
      this.clickExOk();
    }
  }

  clickImport() {
    this.setState({ showImModal: true });
  }

  /**
   * 确认导出
   */
  clickExOk() {

    // 先查询此应用是否已经配置了模板
    reqGet(apiConfig.isCreateConfApi, { appCode: this.props.appCode }).then(rsp => {
      if (false === rsp) {
        message.error('操作失败：系统未配置导出模板文件');
      } else {
        // 不需要显示导出弹框，直接导出全部
        if (false === this.props.needExModal) {
          this._exFunc({ exType: 1 });
        } else if (this.exFormRef && this.exFormRef.getAjaxData) {
          this.exFormRef.getAjaxData().then(this._exFunc.bind(this)).catch(e => {
          });
        }
      }
    });

  }

  _exFunc(values) {
    const $this = this;
    const { appCode, searchData, selectedKeys } = $this.props;
    // console.log(values);
    if (appCode) {
      let ajaxData = {};
      // 导出全部
      if (1 == values.exType && !isEmpty(searchData)) {
        ajaxData = formatFilter(searchData);
      }
      // 导出选中
      else {
        if (!isEmpty(selectedKeys)) {
          ajaxData = formatFilter({
            filterData: {
              id: {
                expression: 'IN',
                value: isArray(selectedKeys) ? selectedKeys.join(',') : selectedKeys,
              },
            },
          });
        } else {
          message.warning('无选中记录');
          return;
        }
      }

      console.log('ajaxData', ajaxData);

      this.abortCtrls.export = newAbortCtrl();
      ajaxData.signal = this.abortCtrls.export.signal;

      $this.setState({ exLoading: true });
      return jsonPost(apiConfig.exportAPi, ajaxData, {
        params: { appCode },
      }).then(rsp => {
        if (rsp && rsp.status === 200 && rsp.data) {
          sleepFunc(1500).then(() => {
            this.needReqResult = true;
            $this.reqExResult(rsp.data);
          });
        } else {
          $this.setState({ exLoading: false });
        }
      });

    }

  }

  /**
   * 取消导出
   */
  clickExCancel() {
    this.abortAllFetch('ex');
    this.setState({ showExModal: false, exLoading: false });
  }

  /**
   * 查询导出结果，如果没完成，则轮询查询接口
   * @param statusKey
   */
  reqExResult(statusKey) {
    const $this = this;
    let newAbortIns, taskGroup, resultKey, loadingKey;

    this.abortCtrls.exResult = newAbortCtrl();
    newAbortIns = this.abortCtrls.exResult;
    taskGroup = 'EXPORT_DATA';
    resultKey = 'needReqResult';
    loadingKey = 'exLoading';

    reqGet(apiConfig.exResultAPi, {
      statusKey,
      taskGroup,
      signal: newAbortIns.signal,
    }).then(rsp => {
      if (rsp && rsp.status === 200 && rsp.data) {

        if (2 == rsp.data.status) {

          if (rsp.data.filePath || rsp.data.fileName) {
            window.open(rsp.data.filePath || rsp.data.fileName, '_blank');
          }
          $this[resultKey] = false;
          const tmpO = {};
          tmpO[loadingKey] = false;
          $this.setState(tmpO);

        } else {
          sleepFunc(1000).then(() => {

            if ($this[resultKey]) {
              $this.reqExResult(statusKey);
            } else {
              const tmpO = {};
              tmpO[loadingKey] = false;
              $this.setState(tmpO);
            }
          });
        }
      } else {
        $this[resultKey] = false;
        const tmpO = {};
        tmpO[loadingKey] = false;
        $this.setState(tmpO);
      }
    });
  }

  /**
   * 导入文件之后的回调
   * @param isAllImport Boolean 是否全部文件都导入了
   * @param importStatus Number  1: 正在导入；2:导入成功；3:导入失败
   */
  afterImport(isAllImport, importStatus) {
    const { afterImportCb } = this.props;
    this.setState({ imLoading: !isAllImport }, () => {
      if (2 == importStatus && afterImportCb) {
        afterImportCb();
      }
    });
  }

  /**
   * 关闭导入浮层
   */
  clickImCancel() {
    this.setState({ showImModal: false });
  }

  render() {
    const { exModalProps, imModalProps, cn, cnInBtn, appCode, actType, needExModal, disabled } = this.props;

    const exProps = {
      visible: this.state.showExModal, // 是否显示
      loading: false, // 是否正在加载
      title: `导出${cn}`,
      action: null, // 自定义操作按钮
      onOk: this.clickExOk.bind(this), // 点击确认后的回调
      onCancel: this.clickExCancel.bind(this), // 点击取消后的回调
      confirmLoading: this.state.exLoading,
      ...exModalProps,
    };
    const imProps = {
      visible: this.state.showImModal, // 是否显示
      loading: false, // 是否正在加载
      title: `导入${cn}`,
      action: null, // 自定义操作按钮
      footer: null,
      bodyStyle: { padding: 0 },
      onCancel: this.clickImCancel.bind(this), // 点击取消后的回调
      ...imModalProps,
    };

    return (
      <>
        {
          'im' === actType ? null : (
            <>
              <ExportDataBtn disabled={disabled} onClick={this.clickExport.bind(this)}
                      loading={this.state.exLoading}>导出{cnInBtn ? cn : ''}</ExportDataBtn>
              {
                needExModal && (
                  <ModalComp {...exProps}>
                    <ExPortForm
                      cn={cn}
                      selectedKeys={this.props.selectedKeys}
                      onRef={(ref) => {
                        this.exFormRef = ref;
                      }}
                    />
                  </ModalComp>
                )
              }
            </>
          )
        }
        {
          'ex' === actType ? null : (
            <>
              <ImportExcelBtn disabled={disabled} onClick={this.clickImport.bind(this)}
                      loading={this.state.imLoading}>导入{cnInBtn ? cn : ''}</ImportExcelBtn>
              <ModalComp {...imProps}>
                <ImportForm
                  appCode={appCode}
                  cn={cn}
                  onCancel={this.clickImCancel.bind(this)}
                  afterImport={this.afterImport.bind(this)}
                />
              </ModalComp>
            </>
          )
        }
      </>
    );
  }
}

ExportComp.defaultProps = {
  cn: '',
  appCode: '',
  searchData: {},
  exModalProps: {},
  actType: '', // String 操作类型，'all'或者'': 导入导出;'ex':导出; 'im':导入
  needExModal: true, // Boolean 是否需要显示导出弹框
  cnInBtn: false, // Boolean 是否将 cn 显示到按钮
  disabled: false,
};

export default ExportComp;
